home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-05-21 | 6.8 KB | 188 lines | [TEXT/ttxt] |
- -- <<<-
-
- -- eventdsp.sx
- -- Event Dispatcher example
- -- by Howard Metzenberg
- -- have yourself a rilly big one
- -- from "Events and Input Devices" chapter of
- -- ScriptX Components Guide
-
- module EventTest2 uses ScriptX end
- in module EventTest2
-
- class EventDispatcher (RootObject)
- instance variables
- interestList -- KeyedLinkedList
- thread -- a thread for responding to user actions
- eventQueue -- use this queue to receive events
- instance methods
- method init self #rest args -> (
- self.interestList := new KeyedLinkedList
- -- note that the event queue replaces the condition
- -- in the Dispatcher class, in the Threads chapter
- -- the queue itself acts as a gate
- self.eventQueue := new EventQueue thread:(self.thread)
- self.thread := new Thread func:dThreadFn arg:self priority:@system
- apply nextMethod self args
- )
- end -- (Dispatcher class definition)
-
- method addInterest self {class EventDispatcher} eventClass func data -> (
- -- check that func is a kind of function
- if isAKindOf func AbstractFunction then (
- -- check that eventClass is a class, and that it inherits from Event
- if isAKindOf eventClass RootClass and isSub eventClass Event then (
- local newInterest
- newInterest := New eventClass
- newInterest.authorData := func
- newInterest.eventReceiver := self.eventQueue
- newInterest.priority := 2
- addEventInterest newInterest
- add self.interestList newInterest data
- ) else (
- format debug "Second argument must be an event class!/n" \
- undefined @normal
- )
- ) else (
- format debug "Third argument must be a function or generic!/n" \
- undefined @normal
- )
- )
- method removeInterest self {class EventDispatcher} eventClass -> (
- -- check that eventClass is currently defined
- -- and that the event dispatcher has as an interest in it
- if isAKindOf eventClass RootClass and isSub eventClass Event then (
- local i := iterate self.interestList
- repeat while (next i) do (
- if (getClass i.key = eventClass) do (
- removeEventInterest i.key
- excise i -- this deletes it from the collection
- exit -- remove only the first occurrence
- )
- )
- ) else (
- format debug "Second argument must be an event class!/n" \
- undefined @normal
- )
- )
-
- function dThreadFn dispatcher -> (
- local myEvent := undefined
- local data := undefined
- repeat while (myEvent := read dispatcher.eventQueue) do (
- -- figure out how the event was delivered and
- -- get the data that goes with the associated interest
- if isAKindOf (myEvent.matchedInterest) Event then (
- -- must have been delivered by signal method
- accept myEvent
- data := dispatcher.interestList[myEvent.matchedInterest]
- -- call the function with event and data as arguments
- (myEvent.matchedInterest.authorData) myEvent data
- ) else (
- -- event could not have been signaled, so see if broadcast
- -- if matchedInterest is undefined, it must have been delivered
- -- using the sendToQueue method
- if myEvent.matchedInterest <> undefined then (
- -- matchedInterest can have one of three values
- -- it can be an event, an array of events, or undefined
- -- it must have been delivered by broadcast method
- -- get an iterator for the array of matching interests
- -- this next line creates a sequence iterator i
- local i := iterate (myEvent.matchedInterest)
- local myClass := getClass myEvent
- -- now iterate through the matchedInterest collection
- repeat while (next i) do (
- -- make sure it is one of our own interests
- -- see if the matching interest is in our own list
- -- if not, then go on to the next matched interest
- if getOne dispatcher.interestList (i.value) = empty do (
- continue -- so skip and go on to the next
- )
- data := dispatcher.interestList[i.value]
- -- call the function with event and data as arguments
- (i.value.authorData) myEvent data
- -- excise it in case there were other event interests
- -- in our own private list.
- -- this only removes it from the collection of interests
- -- that matched the current event. It is still
- -- registered as an interest to receive future events.
- excise i
- exit
- ) -- end repeat
- ) else (
- -- must have been delivered by sendToQueue method
- format debug "not interested in this event!\n" undefined @normal
- myEvent := undefined
- continue -- ignore this event, go back and wait for another
- )
- )
- -- reset it so the thread will block until the next event comes along
- myEvent := undefined
- )
- )
-
- -- now create three new classes of events to test it with
- class GrokEvent (Event) end
- class VoodooEvent (Event) end
- class EarthQuakeEvent (Event) end
- -- create an instance of EventDispatcher
- global gDispatcher := new EventDispatcher
- -- the init method on Dispatcher automatically creates a thread
- -- define some functions that will be called
- global fn func1 myEvent x -> (
- format debug "Function 1 just got a %* event " (getClass myEvent) @normal
- format debug "and its argument is %*.\n" x @normal
- )
- global fn func2 myEvent x -> (
- format debug "Function 2 just got a %* event " (getClass myEvent) @normal
- format debug "and its argument is %*.\n" x @normal
- )
- global fn func3 myEvent x -> (
- format debug "Function 3 just got a %* event " (getClass myEvent) @normal
- format debug "and its argument is %*.\n" x @normal
- )
- -- now create some interests in the three kinds of events
- -- add them to the interest list, with their associated functions and arguments
- addInterest gDispatcher GrokEvent func1 "moof"
- addInterest gDispatcher VoodooEvent func2 "foo"
- addInterest gDispatcher EarthQuakeEvent func3 "7.1"
- addInterest gDispatcher EarthQuakeEvent func1 "8.7"
-
- -- create some events and send them
- global myGrokEvent := new GrokEvent
- global myVoodooEvent := new VoodooEvent
- global prittyBigOne := new EarthQuakeEvent
- global rillyBigOne := new EarthQuakeEvent
- signal myGrokEvent true
- signal myVoodooEvent true
- broadcast prittyBigOne
- broadcast rillyBigOne
-
- -- create an event receiver and associated event interests
- function eventEater event interest data -> (
- format debug "eventEater just received an event. \n" undefined @normal
- format debug "authorData: %* \n" event @normal
- format debug "Interest: %* \n" interest @normal
- format debug "Event: %* \n" data @normal
- )
- global shakeInterest := new EarthQuakeEvent
- shakeInterest.authorData := "No function at all!"
- shakeInterest.priority := 1 -- this one has higher priority
- shakeInterest.eventReceiver := eventEater
- addEventInterest shakeInterest
- global rattleInterest := new EarthQuakeEvent
- rattleInterest.authorData := "Definitely not a function!"
- rattleInterest.priority := 3 -- this one has lower priority
- rattleInterest.eventReceiver := eventEater
- addEventInterest rattleInterest
-
- -- now create some more events and signal them
- global mightyOne := new EarthQuakeEvent
- global awesomeOne := new EarthQuakeEvent
- global giantOne := new EarthQuakeEvent
- broadcast mightyOne
- broadcast awesomeOne
- sendToQueue giantOne gDispatcher.eventQueue
-
- -- >>>
-